package com.elitel.frame.business.controller;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import com.alibaba.fastjson.JSON;
import com.elitel.common.exception.SingleModeMismatchException;
import com.elitel.common.messageQueue.RabbitMQHelper;
import com.elitel.common.utils.XCommonUtils;
//import com.elitel.common.redis.service.RedisCacheService;
import com.elitel.frame.base.component.RedisCacheCfgMaster;
import com.elitel.frame.base.component.RedisCacheComponent;
import com.elitel.frame.base.service.BaseFieldaddonsService;
import com.elitel.frame.base.service.BaseFieldconfigService;
import com.elitel.frame.base.service.BaseShowfieldService;
import com.elitel.frame.base.service.CfgTableService;
import com.elitel.frame.business.service.ExtMasterService;
import com.elitel.frame.business.service.TableFieldCommService;
import com.elitel.frame.main.entity.BaseFieldaddons;
import com.elitel.frame.main.entity.CfgDb;
import com.elitel.frame.main.entity.CfgExtmaster;
import com.elitel.frame.main.entity.CfgTable;
import com.elitel.frame.main.entity.CfgTableFieldCustomAlias;
import com.elitel.frame.main.entity.constant.DictionaryConstant;
import com.elitel.frame.main.entity.ext.BaseMasterdetailExt;
import com.elitel.frame.main.entity.ext.BaseShowfieldExt;
import com.elitel.frame.main.entity.vo.JsonDataResult;
import com.elitel.frame.main.entity.vo.PageResponseVo;
import com.elitel.frame.main.entity.vo.ServerStatistics;

import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;


/**
 * 
 * <pre>@ProjectName：frame-business-web    
 * @ClassName：ExtMasterController    
 * @Description: TODO(主从表服务控制层主表服务)    
 * @author：FanWenquan  
 * @date：2017年10月13日 下午1:51:03       
 * @version </pre>
 */
@Controller
@RequestMapping("/business/extMasterServer")
@Api(value = "/business/extMasterServer", tags = "主从表服务接口")
public class ExtMasterController {
	
	private static final Logger logger = LoggerFactory.getLogger(ExtMasterController.class);
	
	@Autowired
	private RedisCacheCfgMaster redisCacheCfgMaster;
//	@Autowired
//	private RedisCacheService redisCacheService;
	@Autowired
	private RedisCacheComponent redisCacheComponent;
	@Autowired
	private ExtMasterService extMasterService;
	@Autowired
	private BaseFieldaddonsService baseFieldaddonsService;
	@Autowired
	private BaseFieldconfigService baseFieldconfigService;
	@Autowired
	private CfgTableService CfgTableService;
	@Autowired
	private TableFieldCommService tableFieldCommService;

	@Autowired
	private BaseShowfieldService baseShowFieldService;

	@Autowired
	private RabbitMQHelper rabbitMQHelper;

	
	/**
	 * <pre>queryMasterTableList(主从表服务主表服务查询)   
	 * @author：FanWenquan    
	 * @date：2017年10月13日 下午2:39:01   
	 * @param serviceID
	 * @param pageNO
	 * @param pageSize
	 * @param conQuery
	 * @return</pre>
	 */
	@ApiOperation(value = "根据服务编码查询主从表信息")
	@ApiImplicitParams({ 
		@ApiImplicitParam(name="serviceID", value="服务编码", required=true, dataType="String", paramType="query"),
		@ApiImplicitParam(name="pageNO", value="当前页码", required=false, dataType="String", paramType="query"),
		@ApiImplicitParam(name="pageSize", value="每页条数", required=false, dataType="String", paramType="query"),
		@ApiImplicitParam(name="conQuery", value="查询条件集合", required=false, dataType="String", paramType="query")
	})
	@RequestMapping(value="/queryMasterTableList", method = RequestMethod.GET)
	@ResponseBody
	public Object queryMasterTableList(@RequestParam("serviceID") String serviceID, 
										String pageNO, 
										String pageSize, 
										String conQuery){
		ServerStatistics serverRecorder = ServerStatistics.createAndStartRecord();
		CfgExtmaster extmaster = redisCacheCfgMaster.cfgMsaterRedisCache(serviceID);
		CfgDb cfgDb = redisCacheComponent.cfgDBRedisCache(extmaster.getDbKey());

		serverRecorder.recordSqlStartTime();
		try {

			PageResponseVo pageResponse = null;

			pageResponse = extMasterService.queryMasterTablePagination(cfgDb, extmaster, pageNO, pageSize, conQuery);
			pageResponse.computeFirstRowPosition(pageNO, pageSize);

			// here is page response total is more than size 1 ,throw SingleModeMismatchException
			if(XCommonUtils.isSingleResponseMode(extmaster)){
				if(pageResponse.getTotal() != null && pageResponse.getTotal() > 1)
					throw new SingleModeMismatchException();

				return JsonDataResult.responseSuccess(pageResponse.getRows().get(0), extmaster.getResponseMode());
			}


			return JsonDataResult.responseSuccess(pageResponse, extmaster.getResponseMode());

		} catch (SingleModeMismatchException e){
			logger.error("主从表查询服务主表查询服务异常：查询数据量大于一行", e);
			return JsonDataResult.responseError("主从表查询服务主表查询服务异常: 查询数据量大于一行", extmaster.getResponseMode());

		} catch (Exception e) {
			logger.error("主从表查询服务主表查询服务异常：", e);
			return JsonDataResult.responseError("主从表查询服务主表查询服务异常:"+e.getMessage(), extmaster.getResponseMode());

		} finally {
			serverRecorder.recordSqlEndTime();
			serverRecorder.recordServerEndTime();
			serverRecorder.setServerName(extmaster.getServicename() + "(" + serviceID + ")  (master service)");
			rabbitMQHelper.recordTimeConsumeIfNecessary(serverRecorder);
		}
	}
	
	/**
	 * <pre>querySlaveTBbyMasterID(查询从表数据集合)   
	 * @author：FanWenquan    
	 * @date：2017年10月16日 下午12:04:00   
	 * @param serviceID
	 * @param guid
	 * @return</pre>
	 */
	@ApiOperation(value = "根据服务编码和主表主键获取从表信息")
	@ApiImplicitParams({ 
		@ApiImplicitParam(name="serviceID", value="服务编码", required=true, dataType="String", paramType="query"),
		@ApiImplicitParam(name="guid", value="主表主键编码", required=true, dataType="String", paramType="query")
	})
	@RequestMapping(value="/querySlaveTBbyMasterID", method = RequestMethod.GET)
	@ResponseBody
	public Object querySlaveTBbyMasterID(@RequestParam("serviceID") String serviceID, @RequestParam("guid")String guid){
		ServerStatistics serverRecorder = ServerStatistics.createAndStartRecord();

		CfgExtmaster extmaster = redisCacheCfgMaster.cfgMsaterRedisCache(serviceID);
		CfgDb cfgDb = redisCacheComponent.cfgDBRedisCache(extmaster.getDbKey());

		serverRecorder.recordSqlStartTime();
		try {
			Object slaveResult = extMasterService.querySlaveTBList(cfgDb, extmaster, guid);

			return JsonDataResult.responseSuccess(slaveResult, extmaster.getResponseMode());

		} catch (Exception e) {
			logger.error("主从查询服务查询从表数据集合异常:", e);
			return JsonDataResult.responseError("主从查询服务查询从表数据集合异常:"+e.getMessage(), extmaster.getResponseMode());

		}finally{
			serverRecorder.recordSqlEndTime();
			serverRecorder.recordServerEndTime();
			serverRecorder.setServerName(extmaster.getServicename() + " (" + serviceID +  ") (slave service)");
			rabbitMQHelper.recordTimeConsumeIfNecessary(serverRecorder);
		}
	}
	
	/**
	 * 
	 * @Title: queryTableShowField 
	 * @Description: TODO(根据服务ID返回主表显示字段信息) 
	 * @author guoyanfei
	 * @return Object
	 * @throws
	 */
	@ApiOperation(value = "根据服务编码查询列表显示字段信息")
	@ApiImplicitParams({ 
		@ApiImplicitParam(name="serviceID", value="服务编码", required=true, dataType="String", paramType="query") 
	})
	@RequestMapping(value="queryTableShowField", method = RequestMethod.GET)
	@ResponseBody
	public Object queryTableShowField(@RequestParam("serviceID")String serviceID){
		CfgExtmaster cfgExtmaster = redisCacheCfgMaster.cfgMsaterRedisCache(serviceID);
		if(cfgExtmaster == null){
			return JsonDataResult.responseError("can't find cfgExtMaster");
		}

		try {
			List<Map<String,String>> result = null;
			CfgDb cfgDb = redisCacheComponent.cfgDBRedisCache(cfgExtmaster.getDbKey());

			CfgTable cfgTable = CfgTableService.queryCfgTable(cfgExtmaster.getDtConfigId());
			if(XCommonUtils.isOriginSingleTableType(cfgTable.getDtTabletype())){

				result = tableFieldCommService.getServiceShowField(cfgDb, cfgExtmaster.getGuid(), DictionaryConstant.MasterSlaveTableServiceInBaseQuerySql,"");
				return JsonDataResult.responseSuccess(result);
			}

			List<BaseShowfieldExt> showFieldExtList = tableFieldCommService.getServiceShowFieldForView(cfgDb, cfgExtmaster.getGuid(), DictionaryConstant.MasterSlaveTableServiceInBaseQuerySql, "");
			if(XCommonUtils.isEmpty(showFieldExtList))
				return JsonDataResult.responseSuccess(result);

			// find alterName
			List<BaseFieldaddons> baseFieldaddonsList = baseFieldaddonsService.selectFieldaddonsBydtconfigid(cfgTable.getDtConfigId());
			if(XCommonUtils.isEmpty(baseFieldaddonsList))
				return JsonDataResult.responseSuccess(result);
			Map<String, List<BaseFieldaddons>> baseFieldaddonsListMap = baseFieldaddonsList.stream().collect(Collectors.groupingBy(BaseFieldaddons :: getGuid));

			// here is iterate base show field ext , assemble map (filed , type , fieldNameCN)
			List<Map<String, String>> resultMapList = new ArrayList<Map<String, String>>();
			for(BaseShowfieldExt baseShowFieldExt : showFieldExtList){

				String fieldName = null;
				if(XCommonUtils.isNotEmpty(baseShowFieldExt.getCustomAlias())){
					fieldName = baseShowFieldExt.getCustomAlias();
				}else{
					BaseFieldaddons baseFieldAddons = baseFieldaddonsListMap.get(baseShowFieldExt.getFieldaddonsguid()).get(0);
					fieldName = baseFieldAddons.getAltername() + "_" + baseShowFieldExt.getFieldname();
				}

				String fieldNameCN = XCommonUtils.isEmpty(baseShowFieldExt.getCustomFieldNameAlias()) ? baseShowFieldExt.getFieldnameCn() : baseShowFieldExt.getCustomFieldNameAlias();

				Map<String, String> map = new LinkedHashMap<String,String>();
				map.put("fieldname",fieldName);
				map.put("fieldnamecn",fieldNameCN);
				map.put("fieldtype",baseShowFieldExt.getFieldtype());
				resultMapList.add(map);
			}

			return JsonDataResult.responseSuccess(resultMapList);


		} catch (Exception e) {
			logger.error("主从表查询服务查询主表显示字段异常:",e);
			return JsonDataResult.responseError("主从表查询服务查询主表显示字段异常:"+e.getMessage());
		}
	}
	
	
	/**
	 * 
	 * @Title: queryTableQueryField 
	 * @Description: TODO(根据服务ID返回主表查询字段信息) 
	 * @author guoyanfei
	 * @return Object
	 * @throws
	 */
	@ApiOperation(value = "根据服务编码查询主表查询字段信息")
	@ApiImplicitParams({ 
		@ApiImplicitParam(name="serviceID", value="服务编码", required=true, dataType="String", paramType="query") 
	})
	@RequestMapping(value="/queryTableQueryField", method = RequestMethod.GET)
	@ResponseBody
	public Object queryTableQueryField(@RequestParam("serviceID") String serviceID){
		JsonDataResult jsonResult = new JsonDataResult();
		List<Map<String,String>> result = new ArrayList<>();
		try {
			if(serviceID != null && serviceID.isEmpty() == false){
				CfgExtmaster cfgExtmaster = redisCacheCfgMaster.cfgMsaterRedisCache(serviceID);
				if(cfgExtmaster != null){
					CfgDb cfgDb = redisCacheComponent.cfgDBRedisCache(cfgExtmaster.getDbKey());
					result = tableFieldCommService.getTableQueryField(cfgDb, serviceID, 2,"");
				}
				jsonResult.setResult(0);
				jsonResult.setMessage("查询成功!");
				jsonResult.setData(result);
			}
		} catch (Exception e) {
			logger.error("主从表查询服务主从查询字段服务异常：", e);
			jsonResult.setResult(1);
			jsonResult.setMessage("主从表查询服务主从查询字段服务异常："+e.getMessage());
		}
		
		return jsonResult;

	}
	
	/**
	 * 
	 * @Title: queryTableDetailShowField 
	 * @Description: TODO(根据服务ID返回从表显示字段信息) 
	 * @author guoyanfei
	 * @return Object
	 * @throws
	 */
	@ApiOperation(value = "根据服务编码查询从表显示字段信息")
	@ApiImplicitParams({ 
		@ApiImplicitParam(name="serviceID", value="服务编码", required=true, dataType="String", paramType="query") 
	})
	@RequestMapping(value="queryTableDetailShowField", method = RequestMethod.GET)
	@ResponseBody
	public Object queryTableDetailShowField(@RequestParam("serviceID") String serviceID){
		JsonDataResult jsonResult = new JsonDataResult();
		Map<String, Object> resultmap = new LinkedHashMap<String, Object>();
		try {
			CfgExtmaster cfgExtmaster = redisCacheCfgMaster.cfgMsaterRedisCache(serviceID);
			List<BaseMasterdetailExt> baseMasterdetails = redisCacheCfgMaster.getMasterdetailbyMguid(serviceID);
			if(baseMasterdetails != null){
				for (BaseMasterdetailExt baseMasterdetail : baseMasterdetails) {
					List<Map<String,String>> result = new ArrayList<>();
					CfgDb cfgDb = redisCacheComponent.cfgDBRedisCache(cfgExtmaster.getDbKey());
					result = tableFieldCommService.getServiceShowField(cfgDb, baseMasterdetail.getMguid(),"2",baseMasterdetail.getGuid());
					String jsonlist = JSON.toJSONString(result);
					resultmap.put(baseMasterdetail.getDtConfigCh(), jsonlist);
				}
			}
			jsonResult.setResult(0);
			jsonResult.setMessage("查询成功!");
			jsonResult.setData(resultmap);
			
		} catch (Exception e) {
			logger.error("主从表查询服务查询从表显示字段异常:",e);
			jsonResult.setResult(1);
			jsonResult.setMessage("查询失败!");
			jsonResult.setData("主从表查询服务查询从表显示字段异常:"+e.getMessage());
		}
		
		return jsonResult;
	}
	
	/**
	 * @Title: queryMasterTablePrimaryKey 
	 * @Description : 通过服务ID查询主表主键字段
	 * @param serviceID
	 * @return 主键字段
	 * @author guoyanfei
	 */
	@ApiOperation(value = "根据服务编码查询主表主键字段信息")
	@ApiImplicitParams({ 
		@ApiImplicitParam(name="serviceID", value="服务编码", required=true, dataType="String", paramType="query") 
	})
	@RequestMapping(value="/queryMasterTablePrimaryKey", method = RequestMethod.GET)
	@ResponseBody
	public Object queryMasterTablePrimaryKey(@RequestParam("serviceID") String serviceID){
		if(XCommonUtils.isEmpty(serviceID))
			return JsonDataResult.responseParameterError("serviceID is mission");

		CfgExtmaster cfgExtmaster = redisCacheCfgMaster.cfgMsaterRedisCache(serviceID);

		if(cfgExtmaster == null)
			return JsonDataResult.responseError("not find cfgExtmaster");

		try {
			CfgTable cfgTable = CfgTableService.getInfoByDtconfigId(cfgExtmaster.getDtConfigId());
			if(cfgTable ==null)
				return JsonDataResult.responseError("not find cfgTable");

			// here is get all alias column in base_showfield (need to judge which is primary key, now only consider one primary key) here is primary key
			List<CfgTableFieldCustomAlias> primaryKeyCustomAliasList = baseShowFieldService.getCfgTablePrimaryKeyCustomAliasByServiceId(cfgTable.getDtTabletype(), serviceID);

			// here add judge view
			String[] primaryKeys = cfgTable.getDtPrimarykey().split(",");

			if(XCommonUtils.isOriginSingleTableType(cfgTable.getDtTabletype()))
				return handlePrimaryKeyForTable(primaryKeyCustomAliasList, primaryKeys, cfgTable);

			else
				return handlePrimaryKeyForView(cfgTable, primaryKeyCustomAliasList, primaryKeys);


		} catch (Exception e) {
			logger.error("主从表查询服务查询主表主键字段异常:", e);
			return JsonDataResult.responseError("主从表查询服务查询主表主键字段异常:"+e.getMessage());
		}
	}

	private Object handlePrimaryKeyForTable(List<CfgTableFieldCustomAlias> primaryKeyCustomAliasList, String[] primarykeys, CfgTable cfgTable){
		if(primaryKeyCustomAliasList == null){
			return JsonDataResult.responseSuccess(cfgTable.getDtPrimarykey());
		}

		StringBuilder sb = new StringBuilder();
		// by base_showField customAlias is not null to find base_fieldAddsons , then can find relative cfg_field
		// then replace correspond alias for primary key
		boolean replaceByAlias = false;
		for(String primaryKey : primarykeys){
			for(CfgTableFieldCustomAlias primaryKeyCustomAlias : primaryKeyCustomAliasList){
				if(!primaryKey.equals(primaryKeyCustomAlias.getFieldName()))
					continue;

				// here is replace fieldName by customAlias
				sb.append(primaryKeyCustomAlias.getCustomAlias() + ",");
				replaceByAlias = true;
				break;
			}

			if(replaceByAlias){
				replaceByAlias = false;
				continue;
			}

			sb.append(primaryKey + ",");
		}

		if(sb.length() >1 ){
			sb.setLength(sb.length() - 1); //remove final comma
		}

		return JsonDataResult.responseSuccess(sb.length() == 0 ? cfgTable.getDtPrimarykey() : sb.toString());
	}

	private Object handlePrimaryKeyForView(CfgTable cfgTable, List<CfgTableFieldCustomAlias> primaryKeyCustomAliasList, String[] primaryKeys){
		// here is primary key , iterate primarykeys , like origin table if find use customAlias
		List<BaseFieldaddons> baseFieldaddonsList = baseFieldaddonsService.selectFieldaddonsBydtconfigid(cfgTable.getDtConfigId());
		if(XCommonUtils.isEmpty(baseFieldaddonsList)){
			return JsonDataResult.responseSuccess(cfgTable.getDtPrimarykey());
		}

		Map<String, List<BaseFieldaddons>> baseFieldAddonsListMap = baseFieldaddonsList.stream().collect(Collectors.groupingBy(BaseFieldaddons :: getGuid));
		String alterName = baseFieldaddonsList.get(0).getAltername();

		if(primaryKeyCustomAliasList == null){
			return JsonDataResult.responseSuccess(alterName + "_" + cfgTable.getDtPrimarykey());
		}

		StringBuilder sb = new StringBuilder();

		// by base_showField customAlias is not null to find base_fieldAddsons , then can find relative cfg_field
		// then replace correspond alias for primary key
		boolean replaceByAlias = false;
		for(String primaryKey : primaryKeys){
			for(CfgTableFieldCustomAlias primaryKeyCustomAlias : primaryKeyCustomAliasList){
				// here is find alterName
				alterName = baseFieldAddonsListMap.get(primaryKeyCustomAlias.getBaseFieldAddonsGuid()).get(0).getAltername();
				if(!primaryKey.equals(primaryKeyCustomAlias.getFieldName()))
					continue;

				// here is replace fieldName by customAlias
				sb.append(primaryKeyCustomAlias.getCustomAlias() + ",");
				replaceByAlias = true;
				break;
			}

			if(replaceByAlias){
				replaceByAlias = false;
				continue;
			}

			// else alterName in BaseFieldAddons , as PrimaryKey prefix
			sb.append(alterName + "_" + primaryKey + ",");
		}

		if(sb.length() >1 ){
			sb.setLength(sb.length() - 1); //remove final comma
		}


		return JsonDataResult.responseSuccess(sb.toString());
	}
}
